home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / UNIX / PASCAL / PTOC / PTOC.DOC < prev    next >
Text File  |  1992-11-23  |  35KB  |  1,504 lines

  1. .\"            @(#)doc.ms    1.6 Date 87/06/29
  2. .if t .rm CM
  3. .ds LH Holistic Technology AB
  4. .ds CH PTC
  5. .ds RH HD870410-1 Rev: 1.6
  6. .ds LF
  7. .ds CF
  8. .ds RF
  9. .nr LL 6.5i
  10. .nr PO 1i
  11. .nr HM 0.75i
  12. .nr FM 1.5i
  13. .ie t .pl 842p
  14. .el   .pl 72v
  15. .ch BT -\n(FMu/2u
  16. .\" 3 tabs/inch at 12 cpi corresponds to 4 chars/tab
  17. .nr t 1i/3u
  18. .am DS
  19. .ta \ntu +\ntu +\ntu +\ntu +\ntu +\ntu +\ntu +\ntu +\ntu +\ntu +\ntu +\ntu +\ntu +\ntu +\ntu +\ntu +\ntu +\ntu
  20. ..
  21. .LP
  22. .rs
  23. .sp |8c
  24. .nf
  25. .ce 10
  26. .if t .ps +6
  27. .B "PTC implementation note"
  28. .if t .ps -6
  29.  
  30. by
  31.  
  32. Per Bergsten
  33.  
  34. Holistic Technology AB
  35. Grona Gatan 59
  36. 414 54 Gothenburg
  37. Sweden
  38. .ce 0
  39. .sp 12
  40. .LP
  41. This note describes the implementation of ptc, a Pascal to C translator.
  42. The program was developed by Per Bergsten of Holistic Technology AB,
  43. Gothenburg, Sweden.
  44. The paper is intended to provide a guide for those who need to transport
  45. ptc to a new environment,
  46. it describes how Pascal constructs are mapped onto C constructs.
  47. .bp
  48. .NH S 1
  49. Background
  50. .LP
  51. .ds CF - % -
  52. .nr % 1
  53. The aim was originally to provide a simple tool for transporting finished
  54. applications to systems lacking Pascal compilers.
  55. The first versions,
  56. constructed in about 1984,
  57. were capable of translating simple Pascal programs.
  58. It was never intended to become a released product,
  59. however,
  60. as time went by, programs and ambitions grew to the point where nearly
  61. the full Pascal language was supported.
  62. Thus the program as it stands today has a long ancestry
  63. but it has never been redesigned (which it should have been).
  64. .NH 1
  65. Pascal vs C
  66. .LP
  67. To anyone familiar with the two languages it is obvious that
  68. they are very similar in structure.
  69. The major features may be summarised as follows:
  70. .TS
  71. c c
  72. l l .
  73. Pascal    C
  74. .sp
  75. Block-structured    Block-structured
  76. - multiple declaration levels    - single declaration level
  77. Statically scoped    Statically scoped
  78. Strongly typed    Weakly typed
  79.     - allows unbounded pointers
  80. Call by value    Mostly call by value
  81. - and call by reference    
  82. Highly independent    Highly integrated
  83. - of host system    - with system
  84. Self contained    Allows external definitions.
  85. .TE
  86. .LP
  87. On the syntactic level the languages differ only in minor ways,
  88. mostly in the order in which keywords and other symbols occur,
  89. and of course in that the languages uses different symbols for the same
  90. purposes.
  91. The only complication is that C prohibits nested subroutine declarations.
  92. .LP
  93. On the semantic level the situation is worse.
  94. C has the peculiarity that array variables are treated differently from other
  95. variables,
  96. this forces us to adopt some general way to handle array variables.
  97. Furthermore, since Pascal offers nested subroutine declarations
  98. it becomes necessary to simulate part of the activation record mechanism
  99. in the translated code,
  100. in one case it is extremely difficult to completely do this.
  101. It is also clear that the C typedef mechanism has some shortcomings that
  102. preclude an easy translation of Pascal types.
  103. .bp
  104. .NH 1
  105. Mapping Pascal to C
  106. .LP
  107. In this part of the paper we briefly illustrate how to translate
  108. Pascal code into equivalent C code.
  109. .NH 2
  110. Programs
  111. .LP
  112. A minimal Pascal program:
  113. .DS
  114. program p;
  115. begin
  116. end.
  117. .DE
  118. translates to the C equivalent:
  119. .DS
  120. extern void exit(\^);
  121. main(\^)
  122. {
  123.         exit(0);
  124. }
  125. .DE
  126. .LP
  127. It should be noted here that
  128. the translator does not actually require a complete Pascal program,
  129. the implementation is such that any consistent set of declarations can
  130. be translated.
  131. .NH 2
  132. Lexical issues
  133. .LP
  134. The C language uses ASCII as a carrier,
  135. almost all of the availible characters are used.
  136. The Pascal definition uses a smaller set of characters.
  137. Since few features of the languages depend on the underlying character set
  138. this does not introduce much difficulties.
  139. .LP
  140. One serious problem does occur.
  141. Both language definitions states that comments have no meaning and no
  142. clear place in the language syntax.
  143. Furthermore, the Pascal definition states that a comment is equivalent
  144. to a blank character.
  145. This implies that if comments are handled accurately
  146. the translator should also be able to collect and classify each
  147. blank character in a Pascal program and to generate a C program with the
  148. same number of blank characters in the corresponding positions.
  149. This implication conflicts with the fact that the languages have different
  150. syntax rules, it is not obvious what the "corresponding positions" would be.
  151. .LP
  152. Since comments have no defined meaning a user is free to interpret them
  153. in any way and, in particular, to associate them with the surrounding code
  154. in any way s/he chooses.
  155. Although humans usually are able to deduce what bearing a comment has on the
  156. surrounding program code there are no formal rules for how to do this.
  157. Therefore there is no
  158. .I "a priori"
  159. correct way to translate comments
  160. and the translator described here ignores comments altogether.
  161. If/when a reasonable
  162. .I "ad hoc"
  163. solution is found that feature may be incorporated.
  164. .NH 2
  165. Declarations
  166. .LP
  167. The program may introduce local declarations which are handled as follows.
  168. .bp
  169. .NH 3
  170. Labels
  171. .LP
  172. .DS
  173. program p;
  174.  
  175. label    9;
  176.  
  177. begin
  178. 9:
  179.         goto 9
  180. end.
  181. .DE
  182. which we simply translate into:
  183. .DS
  184. extern void exit(\^);
  185. main(\^)
  186. {
  187. L9:
  188.         goto L9;
  189.         exit(0);
  190. }
  191. .DE
  192. 'ne 12
  193. .LP
  194. If the label is reached from an inner procedure:
  195. .DS
  196. program p;
  197.  
  198. label    100;
  199.  
  200.         procedure q;
  201.  
  202.         begin
  203.                 goto 100
  204.         end;
  205.  
  206. begin
  207. 100:
  208. end.
  209. .DE
  210. a more complicated translation must be used:
  211. .DS
  212. # define Line __LINE__
  213. void Caseerror(\^);
  214. # include <setjmp.h>
  215. static struct Jb { jmp_buf jb; } J[1];
  216.  
  217.  void
  218. q(\^)
  219. {
  220.         longjmp(J[0].jb, 100);
  221. }
  222.  
  223. main(\^)
  224. {
  225.         if (setjmp(J[0].jb))
  226.                 goto L100;
  227. L100:
  228.         exit(0);
  229. }
  230. .DE
  231. .LP
  232. We assume the existence of the standard
  233. .I setjmp(\^)
  234. and
  235. .I longjmp(\^)
  236. library functions.
  237. Jumpbuffers are statically allocated as needed depending on the number
  238. of declarationlevels in the program.
  239. .NH 3
  240. Constants
  241. .LP
  242. Constant declarations are treated in two different ways.
  243. Numbers aliases etc are simply
  244. .I "# define" 'd
  245. but string constants are converted to static character arrays in order
  246. to avoid unnecessary duplication of string-constants in the object code,
  247. thus:
  248. .DS
  249. const
  250.     p    = 3.14;
  251.     pie    = '3.14';
  252. .DE
  253. translates to:
  254. .DS
  255. # define pi 3.14
  256. static char pie[\^] = "3.14";
  257. .DE
  258. .NH 3
  259. Types and variables
  260. .LP
  261. Types and variables are mostly easy to translate:
  262. .DS
  263. program p;
  264.  
  265. const length    = 15;
  266.  
  267. type
  268.     struct        = 0 .. length;
  269.     vect        = array [ struct ] of struct;
  270.     color        = (red, blue, ada, yellow);
  271.     pointer    = ^ recd;
  272.     recd        = record
  273.                 r    : pointer;
  274.                 case b : boolean of
  275.                   false:    (c : color);
  276.                   true:    (v : vect);
  277.               end;
  278.  
  279. var    SP        : pointer;
  280.  
  281. begin
  282.     new(SP, true);
  283. end.
  284. .DE
  285. becomes
  286. .DS
  287. typedef char    boolean;
  288. # define false (boolean)0
  289. # define true (boolean)1
  290. extern char *Bools[\^];
  291. # define Unionoffs(p, m) (((long)(&(p)->m))-((long)(p)))
  292. extern char *malloc(\^);
  293. # define length 15
  294. typedef unsigned char C47_struct;
  295. typedef struct { C47_struct A[length + 1]; } vect;
  296. typedef enum { red, blue, ada, yellow } color;
  297. typedef struct S57 *pointer;
  298. typedef struct S57 {
  299.     pointer    r;
  300.     boolean    b;
  301.     union {
  302.         struct {
  303.             color    c;
  304.         } V1;
  305.         struct  {
  306.             vect    v;
  307.         } V2;
  308.     } U;
  309. }    recd;
  310. pointer    sp;
  311.  
  312. main(\^)
  313. {
  314.     sp = (struct S57 *)malloc((unsigned)
  315.         (Unionoffs(sp, U.V2.v) + sizeof(sp->U.V2)));
  316.     exit(0);
  317. }
  318. .DE
  319. The rationale is as follows:
  320. .LP
  321. Identifiers in the Pascal program which conflicts with reserved words in C are
  322. renamed by adding a unique prefix Cnnn where nnn is a number.
  323. .LP
  324. We also note here that uppercase letters in identifiers and keywords
  325. are translated to lowercase.
  326. Pascal specifies that upper/lower case is insignificant whereas C
  327. (for the present) separates the two.
  328. This fact is used to advantage by the translator as all
  329. subroutines and macros defined by the translator have an initial uppercase
  330. letter which prevents confusion.
  331. .IP \-
  332. The type
  333. .I boolean
  334. is a predefined Pascal type,
  335. when it is used the translator emits code which defines boolean to
  336. be the smallest convenient type:
  337. .I char .
  338. The constants
  339. .I false
  340. and
  341. .I true
  342. are defined and the vector
  343. .I Bools
  344. will contain textstrings for output if needed.
  345. .IP \-
  346. The predefined types
  347. .I integer
  348. and
  349. .I real
  350. are likewise mapped directly onto the standard C types
  351. .I int
  352. and
  353. .I double
  354. through a typedef declaration.
  355. .sp
  356. Integer subranges are mapped onto standard C arithmetic types according to
  357. a short table in the translator.
  358. The table is scanned from top to bottom until an enclosing range is found
  359. and the corresponding type-name is emitted.
  360. .IP \-
  361. C-arrays have peculiar semantix.
  362. To unify the treatment of arrays and other datatypes we always encapsulate
  363. an array in a struct,
  364. thus an array always becomes a
  365. .I struct
  366. with a single member named A.
  367. .IP \-
  368. Records and their variants are translated into C
  369. .I struct
  370. and
  371. .I union
  372. definitions.
  373. Since C requires all union members to have a name we must supply artificial
  374. names for all record variants.
  375. A record with variants will therefore always contain one field with the name U
  376. which have sub-fields named Vnnn where nnn is a positive number.
  377. .sp
  378. 'ne 12
  379. When allocating dynamic storage for a record with variants naming
  380. the desired variant
  381. .DS
  382. new(sp, true)
  383. .DE
  384. we face the problem of determining the amount of memory needed.
  385. .QP
  386. .B
  387. C does not provide a safe way
  388. to compute the size of a particular struct variant.
  389. .IP
  390. The strategy adopted to cope with this problem is to attempt to compute the
  391. offset of a fieldmember in the variant matching the constant and then
  392. to add the size of the variant.
  393. The offset computation is expressed as a macro,
  394. .I Unionoffs ,
  395. which uses rather foul typecasting to achive the result.
  396. The only availible alternative would be to use the same size of all variants.
  397. This method,
  398. while being safe,
  399. wastes memory when many small and few large
  400. records of the same type are created dynamically.
  401. .IP \-
  402. Pascal enumeration types are converted directly to C
  403. .I enum
  404. types.
  405. .IP \-
  406. Pascal pointer types are translated into C pointer types.
  407. Pascal allows the programmer to construct recursive types as pointer
  408. types need not be fully defined until the end of the declaration-section
  409. where the pointer type is used.
  410. In practice this is only used to introduce record types which
  411. contain pointers to themselves.
  412. This problem is partially solved by introducing a name for the record type.
  413. .ne 10
  414. Hence
  415. .DS
  416. type
  417.     ptr    = ^ node;
  418.     node    = record
  419.             next    : ptr;
  420.             info    : integer
  421.           end;
  422. .DE
  423. becomes
  424. .DS
  425. typedef struct S56 * ptr;
  426. typedef struct S56 {
  427.     ptr        next;
  428.     integer        info;
  429. } node;
  430. .DE
  431. we note in passing that the problem cannot be completely solved since
  432. .DS
  433. type    pureptr    = ^ pureptr;
  434. .DE
  435. which is valid Pascal, cannot be expressed in C.
  436. .ne 10v
  437. .IP \-
  438. A pascal set-type does not have any direct counterpart in C.
  439. The C language does however have a adequate set of operators for
  440. bit manipulation.
  441. We use these to implement a Pascal set as an array of
  442. .I setword .
  443. So:
  444. .DS
  445. type
  446.     s    = set of 1 .. 100;
  447.  
  448. var
  449.     ss    : s;
  450. .DE
  451. is translated into:
  452. .DS
  453. typedef unsigned short setword;
  454. typedef struct { setword S[8]; } s;
  455.  
  456. s    ss;
  457. .DE
  458. The situation is slightly complicated by the fact that Pascal has
  459. a set constructor which permits the construction of arbitrary large sets,
  460. for example:
  461. .DS
  462. s := [ 50 .. maxint ] * [ 1 .. 80 ]
  463. .DE
  464. for that reason the first member in the array of words gives
  465. size of the set (in words).
  466. In the example above s.S[0] would have the value 7,
  467. and s.S[1] through s.S[7] would hold the bits.
  468. The number 7 is computed on the assumption that the type
  469. .I "unsigned short"
  470. on the target host is sufficiently large to holds 16 bits.
  471. The set operators of Pascal are implemented as C functions returning
  472. pointers to arrays of setwords,
  473. the intermediary results are held in a static area of fixed size.
  474. .IP \-
  475. Pascal files are implemented using the standard i/o package availible
  476. in most C implementations.
  477. Since Pascal has the requirement that the next element of a file is visible
  478. in the filebuffer before it is read,
  479. and the requirement that linemarkers in textfiles are given special treatement
  480. we are forced to extend the
  481. .I FILE
  482. type provided in
  483. .I <stdio.h> .
  484. .ne 20
  485. Hence:
  486. .DS
  487. var    f    : text;
  488. .DE
  489. becomes
  490. .DS
  491. typedef struct {
  492.     FILE    *fp;
  493.     unsigned short
  494.             eoln:1,
  495.             eof:1,
  496.             init:1,
  497.             out:1,
  498.             :12;
  499.     char    buf;
  500. }    text;
  501. text    f;
  502. .DE
  503. where
  504. .I buf
  505. is our filebuffer and
  506. .I eoln ,
  507. .I eof
  508. and
  509. .I init
  510. are flags giving the state of the file.
  511. All Pascal i/o operations are implemented using macros that maintain the flags
  512. and the buffer variable.
  513. The actual reading and writing of data is deferred to the standard i/o package.
  514. .NH 3
  515. Procedures and functions
  516. .LP
  517. Pascal procedures and functions are somewhat difficult to translate to C.
  518. The main problems lie in nested declarations and procedural parameters.
  519. Nested declarations are handled in the following manner:
  520. .RS
  521. .IP \-
  522. If procedure B is declared in procedure A,
  523. then procedure B is emitted before A and A is forward declared before B.
  524. .IP \-
  525. Any constants and types declared in A is moved to the global scope,
  526. this may force renaming of those objects.
  527. .IP \-
  528. Any variable declared in A
  529. .I
  530. and used in B
  531. .R
  532. is converted to a pointer and moved to the global scope.
  533. The pointer value is saved and re-initialized upon each entry of A
  534. and restored upon exit from A.
  535. .RE
  536. .br
  537. 'ne 20
  538. .LP
  539. Hence:
  540. .DS
  541. procedure A;
  542.  
  543. const    limit    = 20;
  544.  
  545. type    loctyp    = 0 .. limit;
  546.  
  547. var    i, j    : loctyp;
  548.  
  549.     procedure B(k : loctyp);
  550.  
  551.     begin
  552.         j := k + 2
  553.     end;
  554.  
  555. begin
  556.     B(i)
  557. end;
  558. .DE
  559. becomes
  560. .DS
  561. typedef unsigned char    loctyp;
  562. loctyp    *G56_j;
  563.  
  564. void a(\^);
  565.  
  566.  void
  567. b(k)
  568.     loctyp  k;
  569. {
  570.     (*G56_j) = k + 2;
  571. }
  572.  
  573.  void
  574. a(\^)
  575. {
  576. # define limit 20
  577.     loctyp  i, j;
  578.     loctyp  *F57;
  579.  
  580.     F57 = G56_j;
  581.     G56_j = &j;
  582.     b(i);
  583.     G56_j = F57;
  584. }
  585. .DE
  586. we see that references to
  587. .I j
  588. inside procedure
  589. .I b
  590. are replaced by the pointer
  591. .I G56_j
  592. which points to the local variable
  593. .I j
  594. in procedure
  595. .I a.
  596. In order to preserve the proper semantix in the face of recursion
  597. the value of the pointer need also be saved in the local variable
  598. .I F57
  599. during the invocation of
  600. .I a .
  601. .IP \-
  602. Procedure parameters offer little problems.
  603. We translate Pascal value-parameters into ordinary C parameters
  604. and Pascal var-parameters are treated as pointers.
  605. .br
  606. 'ne 20
  607. .IP \-
  608. Procedural parameters appear at first to be easy to handle.
  609. The ordinary program:
  610. .DS
  611. program p;
  612.  
  613. procedure pp(procedure q(i : integer));
  614.  
  615. begin
  616.     q(2)
  617. end;
  618.  
  619. procedure qq(i : integer);
  620. begin
  621. end;
  622.  
  623. begin
  624.     pp(qq)
  625. end.
  626. .DE
  627. becomes
  628. .DS
  629. extern void    exit(\^);
  630. typedef int    integer;
  631.  
  632.  void
  633. pp(q)
  634.     void    (*q)(\^);
  635. {
  636.     (*q)(2);
  637. }
  638.  
  639.  void
  640. qq(i)
  641.     integer i;
  642. {
  643. }
  644.  
  645. main(\^)
  646. {
  647.     pp(qq);
  648.     exit(0);
  649. }
  650. .DE
  651. which looks simple enough.
  652. .br
  653. However,
  654. Pascal requires that the scope of a procedure
  655. .I "remains unchanged"
  656. throughout its lifetime.
  657. .ne 35
  658. Consider:
  659. .DS
  660. program demo(output);
  661.  
  662. var    i    : integer;
  663.  
  664.     procedure p(procedure q);
  665.  
  666.     var    j    : integer;
  667.  
  668.         procedure qq;
  669.  
  670.         begin
  671.             writeln(j)
  672.         end;
  673.  
  674.     begin
  675.         j := i;
  676.         q;
  677.         if i < 1 then
  678.           begin
  679.             i := i + 1;
  680.             p(qq)
  681.           end
  682.     end;
  683.  
  684.     procedure dummy;
  685.     begin
  686.     end;
  687.  
  688. begin
  689.     i := 0;
  690.     p(dummy)
  691. end.
  692. .DE
  693. When
  694. .I p
  695. is first invoked it assigns the local variable
  696. .I j
  697. the value 0.
  698. This variable is accessible from
  699. .I qq
  700. which is passed as a parameter in
  701. the recursive call of
  702. .I p .
  703. The second invocation of
  704. .I p
  705. then sets
  706. .I its 
  707. variable
  708. .I j
  709. to 1,
  710. and calls
  711. .I q
  712. which is bound to the first instance of
  713. .I qq ,
  714. and should therefore print the number
  715. .I 0 .
  716. .B
  717. Sadly,
  718. the code produced by the translator fails to do this.
  719. .R
  720. It is obvious that the program above calls for a complete simulation
  721. of the activation record mechanism of Pascal to work correctly.
  722. .RS
  723. .LP
  724. A workable but unpractical solution would be:
  725. .IP 1)
  726. When qq is used as parameter we call a function q1 which saves the environment
  727. for qq (i.e. the address of j) in a well known place
  728. and returns a pointer to q2.
  729. .IP 2)
  730. When qq is later called (under the name q) the actual target will be q2
  731. which sets up the proper environment calls qq.
  732. .RE
  733. .IP
  734. The problem is that this requires a save-area for
  735. .I each
  736. procedural parameter which can hold the intresting
  737. parts of its environment for
  738. .I each
  739. of its invocations.
  740. In the example above we need one are which holds the address of i
  741. for each instance of qq
  742. (say N instances, where N depends on the run-time behaviour of p).
  743. It also requires a set of different procedures to perform the work of q2
  744. (N different procedures which sets up the environment for the N instances).
  745. .B
  746. This requires much to much work to implement so the problem is left unsolved,
  747. .R
  748. this is hardly a problem in practice since humans rarely write such code
  749. but
  750. .B
  751. it could introduce problems
  752. .R
  753. in machine generated Pascal code.
  754. .IP
  755. It should be noted that
  756. the translator accepts the keyword
  757. .B external
  758. in place of the Pascal
  759. .B forward
  760. directive and assumes that the so declared procedure is defined elsewhere.
  761. .bp
  762. .NH 2
  763. Statements.
  764. .LP
  765. Pascal statements are comparatively easy to translate to C.
  766. The only parts that require special care are 
  767. non-local
  768. .I goto ,
  769. .I with
  770. and
  771. .I for
  772. statements.
  773. The code
  774. .DS
  775. program p(output);
  776.  
  777. type
  778.     msgtyp    = packed array [ 1 .. 12 ] of char;
  779.  
  780. var
  781.     a    : array [ 1 .. 10 ] of
  782.             record
  783.                 r    : real
  784.             end;
  785.     i    : integer;
  786.     ok    : boolean;
  787.  
  788.     procedure fatal(m : msgtyp);
  789.  
  790.     begin
  791.         writeln('Fatal error: ', m)
  792.     end;
  793.  
  794. begin
  795.     while true do
  796.       repeat
  797.         ok := false;
  798.         i := 1;
  799.         for i := i + 1 to i + 10 do
  800.             if i > 10 then
  801.                 fatal(' 10 exceeded')
  802.             else
  803.               with a[i] do
  804.                 if r > 9.99e+38 then
  805.                     ok := true
  806.                 else
  807.                     writeln(r)
  808.       until ok
  809. end.
  810. .DE
  811. 'ne 20
  812. becomes
  813. .DS
  814. typedef char boolean;
  815. # define false (boolean)0
  816. # define true (boolean)1
  817. typedef int integer;
  818. typedef double real;
  819.  
  820. typedef struct { char A[12 - 1 + 1]; } msgtyp;
  821. typedef struct { struct    S57 {
  822.     real    r;
  823. }    A[10 - 1 + 1]; }  T56;
  824. T56        a;
  825. integer    i;
  826. boolean    done;
  827.  
  828.  void
  829. fatal(m)
  830.     msgtyp    m;
  831. {
  832.     (void)fprintf(output.fp, "Fatal error: %.12s", m.A),
  833.                     Putchr('\en', output);
  834. }
  835.  
  836. main(\^)
  837. {
  838.     while (true)
  839.       do {
  840.         done = false;
  841.         i = 1;
  842.         {
  843.           integer        B1 = i + 1, B2 = i + 10;
  844.  
  845.           if (B1 <= B2)
  846.             for (i = B1; ; i++) {
  847.                 if (i > 10)
  848.                     fatal(*((msgtyp *)" 10 exceeded"));
  849.                 else {
  850.                     register struct    S57 *W3 = &a.A[i - 1];
  851.  
  852.                     if (W3->r > 9.99e+38)
  853.                         done = true;
  854.                     else
  855.                         (void)fprintf(output.fp, "% 20e", W3->r),
  856.                             Putchr('\en', output);
  857.                 }
  858.                 if (i == B2) break;
  859.             }
  860.         }
  861.       } while (!(done));
  862.     exit(0);
  863. }
  864. .DE
  865. for the following reasons:
  866. .NH 3
  867. Begin
  868. .LP
  869. The compound statements
  870. are very similar in the two languages and need no further explanation.
  871. .NH 3
  872. If
  873. .LP
  874. Pascal if-statements
  875. have the same structure and semantix as C if-statments.
  876. .NH 3
  877. Case
  878. .LP
  879. Pascal case-statements
  880. have the same structure and semantix as C switch-statements provided that a
  881. .I break
  882. is always added to each entry.
  883. .LP
  884. The translator supports a common Pascal extension
  885. in that it recognizes the keyword
  886. .B otherwise
  887. to signify a default entry in a case-statement.
  888. .NH 3
  889. Labels
  890. .LP
  891. Pascal labeled statements and labels have the same structure and semantix as
  892. C labeled statements except that Pascal labels are numbers where C labels
  893. are identifiers,
  894. this difference is solved by simply prefixing the labels with the letter
  895. .I L .
  896. .NH 3
  897. Goto
  898. .LP
  899. Pascal goto-statements
  900. have the same structure as C goto statements but the semantix differ in
  901. that Pascal allows a goto to lead out of the current procedure.
  902. This is implemented using the
  903. .I setjmp/longjmp
  904. library functions of C as described earlier.
  905. .NH 3
  906. With
  907. .LP
  908. The with-statement
  909. of Pascal has no counterpart in C.
  910. It is translated into nested compund statements where pointervariables,
  911. referencing the corresponding records,
  912. are declared and initialized.
  913. Within the scope of the with-statement,
  914. the accessible record fields are renamed to include the pointer.
  915. The effect of this is that the record address is evaluated once as the
  916. Pascal standard requires.
  917. .NH 3
  918. For
  919. .LP
  920. The for-statement
  921. of Pascal has a structure that is similar to the C for-statement
  922. but the semantix differ completely.
  923. Pascal requires that a loop be exited when the upper bound
  924. has been reached,
  925. Pascal also requires that the loop-boundaries be evaluated exactly once.
  926. The standard C for-loop is exited when the loop-condition becomes false.
  927. This implies that it is not always true that
  928. .DS
  929. for (i = 0; i <= e; i++) ;
  930. .DE
  931. behaves in the same manner as
  932. .DS
  933. for i := 0 to e do ;
  934. .DE
  935. since (in most implementations)
  936. the C version becomes an infinite loop if
  937. .I e
  938. equals
  939. .I maxint
  940. or if
  941. .I e
  942. is the expression
  943. .I i .
  944. For that reason Pascal for-statments are translated into compound statements
  945. where the upper/lower bounds of the for-loop are held in local variables.
  946. It is also necessary to add a conditional break-statement at
  947. the end of the loop.
  948. It is possible to obtain the more relaxed translation by configuring the
  949. translator appropriately (see "Tuning" below).
  950. .NH 3
  951. While
  952. .LP
  953. The while-statement behaves exactly the same in both languages.
  954. .NH 3
  955. Repeat
  956. .LP
  957. The repeat-statement of Pascal matches the do-while statement of C except
  958. for the trivial difference that Pascal permits a statement-list
  959. where C permits a single statment in the loop.
  960. .NH 3
  961. Empty
  962. .LP
  963. The empty statement has (of course) the same structure and semantix
  964. in both languages.
  965. .NH 2
  966. Expressions and assignments
  967. .LP
  968. In most cases Pascal expressions can be literally translated into equivalent
  969. C expressions.
  970. .IP identifiers 15
  971. Except where identifiers clash with reserved words or with other
  972. identifiers declared in the same scope,
  973. they may simply be printed.
  974. In some cases the translator is forced to rename identifiers or to
  975. invent new identifiers.
  976. .IP operators
  977. The operators +, -, *
  978. .I div
  979. and
  980. .I mod
  981. when applied to real or integer operands
  982. have exact counterparts in C and are therefore easy to handle.
  983. The operator for real division, /,
  984. corresponds to the same C operator except that the operands may be integers.
  985. In that case a cast is necessary.
  986. When the operands are sets the expression is converted into a function call.
  987. .sp
  988. The operators <, <=, >, >=, = and <> all have exact counterparts in C
  989. for integer and real operands.
  990. Most C implementations disallows
  991. .I enum
  992. operands,
  993. the translator therefore casts such operands to
  994. .I int .
  995. Comparisons on structures (i.e. strings or sets)
  996. are converted into function calls.
  997. .IP assignments
  998. Assignments are straightforward to handle since arrays are encapsulated
  999. in structures.
  1000. Therefore:
  1001. .DS
  1002. a := b
  1003. .DE
  1004. becomes
  1005. .DS
  1006. a = b
  1007. .DE
  1008. .I unless
  1009. b is a string or a set,
  1010. in which case the assignment is converted into a function call.
  1011. .IP indexing
  1012. Given the translation for array declarations (described above) we are forced
  1013. to translate
  1014. .DS
  1015. a[i]
  1016. .DE
  1017. into
  1018. .DS
  1019. a.A[i - c]
  1020. .DE
  1021. where
  1022. .I c
  1023. is the lower bound for the index type.
  1024. .IP selection
  1025. Given the translation for records with variants (described above) the
  1026. translation of
  1027. .DS
  1028. a.b
  1029. .DE
  1030. becomes
  1031. .DS
  1032. a.b
  1033. .DE
  1034. .I or ,
  1035. if b is declared in a variant,
  1036. .DS
  1037. a.Vxxx.b
  1038. .DE
  1039. where Vxxx is a name manufactured by the translator for the particular variant.
  1040. .IP dereferencing
  1041. Pointer references and
  1042. .B var -parameters
  1043. are handled by prefixing the expression with an asterisk,
  1044. but the special case dereferencing followed by selection is also recognized,
  1045. so:
  1046. .DS
  1047. p^ := q^.f
  1048. .DE
  1049. becomes
  1050. .DS
  1051. *p = q->f
  1052. .DE
  1053. .IP miscellanea
  1054. The boolean operators
  1055. .B and ,
  1056. .B or
  1057. and
  1058. .B not
  1059. are simply translated into their C counterparts.
  1060. The set contructors
  1061. .B "[\^]" ,
  1062. and
  1063. .B ".."
  1064. and the operator
  1065. .B in
  1066. are converted to function calls.
  1067. .bp
  1068. .NH 1
  1069. Implementation
  1070. .LP
  1071. The general strategy is to convert the Pascal source program
  1072. into a parsetree.
  1073. The tree is then traversed by a set of procedures that perform some
  1074. necessary transformations.
  1075. The tree is finally traversed by a set of procedures that print the
  1076. corresponding C constructs.
  1077. The translator consists of three major procedures that perform
  1078. these actions.
  1079. They are augmented by a set of procedures that maintain a symbol table
  1080. that holds information about identifiers found in the source,
  1081. and by a procedure that initializes all internal datastructures.
  1082. .LP
  1083. There are three major datastructures that interact in complicated ways:
  1084. .IP 1)
  1085. a store for identifiers and strings
  1086. .IP 2)
  1087. a multilevel symbol table
  1088. .IP 3)
  1089. a parse-tree.
  1090. .LP
  1091. The identifier and string store,
  1092. .B strstor
  1093. is in principle an array of characters that grow
  1094. in increments of one string block.
  1095. Exactly one copy of each identifier is stored in that array.
  1096. Whenever an identifier is found in the input stream the array is
  1097. scanned to see if that identifier has been seen before.
  1098. In order to speed up the search all identifiers are represented by nodes
  1099. which are chained together such that all nodes in a particular chain
  1100. have the same hashvalue as determined by the function
  1101. .B hash .
  1102. Each
  1103. .B idnode
  1104. holds an index to strstor where the corresponding identifier text is stored.
  1105. The start of the hashchains are found in the global variable
  1106. .B idtab .
  1107. .de Ds
  1108. .nr x \\w'\\$2'u
  1109. .ie t \{
  1110. .nr x \\nx/2
  1111. .ds \\$1 \\\\h'-\\nxu'\\$2\\\\h'-\\nxu'
  1112. .\}
  1113. .el .ds \\$1 \\$2\\\\h'-\\nxu'
  1114. ..
  1115. .ds l \-
  1116. .ie t .ds a \z\*l\a
  1117. .el   .ds a \a\z\*l
  1118. .nr x \ntu/2
  1119. .ds g \z\*l\\l'\nxu\&\*l'
  1120. .ds h \\h'\nxu'
  1121. .Ds c +
  1122. .Ds d \(da
  1123. .Ds u \(ua
  1124. .Ds r \(br
  1125. .ds s \\*r\z\*l
  1126. .ds > \*l\z\*l\(->
  1127. .ds < \(<-\\h'-1n'\*l
  1128. .ds k \\kx
  1129. .ds b \\h'|\\nxu'
  1130. .ds t \t
  1131. .DS L
  1132. .lc \*l
  1133. .fc #
  1134. idtab
  1135. \*c\*a\*c
  1136. \*r\*t\*r\*tchain of idnodes with same hashvalue
  1137. \*c\*a\*c\*t\*c\*a\*a\*c\*t\*c\*a\*a\*c
  1138. \*k\*r\*t\*r\*b\*h\*a#\*> #\*r\*t\*k\*t\*r\*b\*h\*a#\*> #\*r\*t\*t\*r idnode representing
  1139. \*c\*a\*c\*t\*r\*t\*t\*r\*t\*k index=2\*b\*r\*t\*t\*r identifier "demo"
  1140. \*r\*t\*r\*t\*c\*a\*a\*c\*t\*c\*a\*a\*c
  1141.  
  1142. \*tstrstor
  1143. \*c\*a\*a\*a\ \*l \*a\*a\*c
  1144. \*r\*t\*r\*t\*r\*t\*t\*r\*t\*r
  1145. \*k\*c\*a\*a\*a\ \*l \*a\*a\*c\*b\*h\*r
  1146. \*h\*r
  1147. \*h\*d
  1148. \*c\*a\*a\*a\*a\*a\*a\*a\*a
  1149. \*r\*t\*r\*t\*r# d #\*r# e #\*r# m #\*r# o #\*r# / #\*r
  1150. \*c\*a\*a\*a\*a\*a\*a\*a\*a\*tfirst idblock
  1151. \*t\*t# \*u #
  1152. \*t\*tindex=2
  1153. .DE
  1154. .LP
  1155. So:
  1156. the global representation of the identifier "demo" is a particlular
  1157. idnode;
  1158. whenever the lexical analysis routine
  1159. recognizes the identifier "demo" it returns a pointer to that idnode.
  1160. .LP
  1161. In order to represent different identifiers with the same name we need to
  1162. be able to distinguish between identifiers declared in different scopes.
  1163. This is accomplished by the
  1164. .B symnode
  1165. structures.
  1166. When an identifier is first encountered in a given scope it is "declared",
  1167. meaning that a new symnode is created that references the identifier.
  1168. Occurrences of the same identifier in that scope are then represented in
  1169. the parse-tree by treenodes referencing the same symnode.
  1170. .bp
  1171. The program:
  1172. .DS
  1173. program p;
  1174.  
  1175. var    demo    : integer;
  1176.  
  1177. begin
  1178.     demo := 3
  1179. end.
  1180. .DE
  1181. yilds the following structure:
  1182. .DS L
  1183. .lc \*l
  1184. .fc #
  1185. \*t# top #
  1186. \*t# \*d #
  1187. \*t\*c\*a\*a\*a\*a\*c treenode representing
  1188. \*t\*k npgm\*b\*r\*t\*t\*t\*t\*r the program
  1189. \*t\*c\*a\*s\*a\*s\*a\*s\*a\*c
  1190. \*t\*t\*r\*t\*r\*h\*u\*t\*r\*h\*u
  1191. \*t\*t\*r\*t\*r\*h\*r\*t\*r\*h\*c\*a\*a\*a\*a\*a\*a\*a\*g\*c
  1192. \*t\*t\*r\*t\*r\*h\*r\*t\*c\*a\*a\*a\*a\*a\*a\*a\*c\*h\*r
  1193. \*t\*t\*r\*t\*d\*h\*r\*t\*t\*t\*t\*t\*t\*t\*t\*r\*h\*r
  1194. \*t\*t\*r\*h\*c\*a\*g\*s\*a\*a\*c\*k treenode representing\*b\*t\*t\*t\*t\*t\*t\*r\*h\*r
  1195. \*t\*t\*r\*h\*k nvar\*b\*r\*t\*t\*t\*\*kr the var-declaration\*b\*t\*t\*t\*t\*t\*t\*d\*h\*r
  1196. \*t\*t\*r\*h\*c\*g\*s\*a\*s\*a\*c\*t\*t\*t\*c\*a\*a\*a\*g\*s\*a\*c treenode repr.
  1197. \*t\*t\*r\*t\*r\*h\*u\*t\*r\*t\*t\*t\*t\*k nassign\*b\*r\*t\*t\*t\*t\*r assignment
  1198. \*t\*t\*r\*t\*r\*h\*r\*t\*c\*a\*k\*> to type\*b\*t\*t\*t\*c\*a\*s\*a\*a\*s\*a\*c
  1199. \*ksymtab\*b\*t\*t\*r\*t\*d\*h\*r\*t\*t\*t\*t\*t\*t\*d\*h\*u\*t\*t\*d\*h\*u
  1200. \*c\*a\*c\*t\*r\*h\*c\*a\*g\*s\*a\*c\*k treenode repr.\*b\*t\*t\*t\*t\*c\*a\*g\*s\*a\*c\*h\*c\*a\*g\*s\*a\*a\*c
  1201. \*r\*t\*r \*<\*a\*c\*h\*k nid\*b\*r\*t\*t\*r\*k occurrence of\*b\*t\*t\*t\*t\*k nid\*b\*r\*t\*t\*r\*h\*k ninteger\*b\*r\*t\*t\*t\*r
  1202. \*t\*t\*h\*c\*a\*s\*a\*c\*k id. "demo"\*b\*t\*t\*t\*t\*c\*a\*s\*a\*c\*h\*c\*a\*a\*s\*a\*c
  1203. \*r\*t\*r\*t\*t\*r\*h\*u\*t\*t\*t\*t\*t\*t\*r\*t\*t\*t\*r\*h\*u
  1204. \*c\*a\*c\*t\*t\*r\*h\*r\*t\*c\*a\*a\*a\*a\*a\*c\*t\*t\*t\*r\*h\*r
  1205. \*r\*t\*r\*t\*t\*d\*h\*r\*t\*d\*t\*t\*t\*t\*t\*t\*t\*t\*d\*h\*r
  1206. \*c\*a\*c\*t\*c\*a\*g\*s\*a\*a\*c\*k symnode representing\*b\*t\*t\*t\*t\*t\*t\*c\*a\*g\*s\*a\*g\*c
  1207. \*r\*k\*t\*r\*b\*h\*a\*>\*t\*k lidentifier\*b\*r\*t\*t\*t\*r\*k identifier "demo"\*b\*t\*t\*t\*t\*t\*t\*k linteger\*b\*r\*t\*t\*h\*r
  1208. \*c\*a\*c\*t\*c\*a\*s\*a\*a\*c\*k in the current scope\*b\*t\*t\*t\*t\*t\*t\*k linum=3\*b\*r\*t\*t\*h\*r
  1209. \*t\*t\*t\*r\*t\*t\*t\*t\*t\*t\*t\*t\*c\*a\*a\*g\*c
  1210. \*kidtab\*b\*t\*t\*t\*c\*a\*a\*a\*c
  1211. \*c\*a\*c\*t\*t\*t\*t\*t\*r
  1212. \*r\*t\*r\*t\*t\*t\*t\*t\*d
  1213. \*c\*a\*c\*t\*c\*a\*a\*c\*t\*c\*a\*a\*c
  1214. \*k\*r\*t\*r\*b\*h\*a#\*> #\*r\*t\*k\*t\*r\*b\*h\*a#\*> #\*r\*t\*t\*r idnode representing
  1215. \*c\*a\*c\*t\*r\*t\*t\*r\*t\*k index=2\*b\*r\*t\*t\*r identifier "demo"
  1216. \*r\*t\*r\*t\*c\*a\*a\*c\*t\*c\*a\*a\*c
  1217.  
  1218. \*tstrstor
  1219. \*c\*a\*a\*a\ \*l \*a\*a\*c
  1220. \*r\*t\*r\*t\*r\*t\*t\*r\*t\*r
  1221. \*c\*g\*s\*a\*a\*a\ \*l \*a\*a\*c
  1222. \*h\*r
  1223. \*h\*d
  1224. \*c\*a\*a\*a\*a\*a\*a\*a\*a
  1225. \*r\*t\*r\*t\*r# d #\*r# e #\*r# m #\*r# o #\*r# / #\*r
  1226. \*c\*a\*a\*a\*a\*a\*a\*a\*a\*tfirst idblock
  1227. \*t\*t# \*u #
  1228. \*t\*tindex=2
  1229. .fc
  1230. .lc
  1231. .DE
  1232. We see that the two occurrences of the identifier "demo" are represented by
  1233. two
  1234. .B treenodes
  1235. of variant
  1236. .B nid
  1237. that both have pointers to the same
  1238. .B symnode
  1239. representing the declaration of "demo".
  1240. All symnodes at a given declarationlevel are chained together (in the
  1241. same manner as the idnodes) and the chains are attached to the global
  1242. variable
  1243. .B symtab .
  1244. In order to find out if an identifer is declared in the current scope we
  1245. scan the chain of symnodes starting from symtab, and check if any of them
  1246. references the idnode we are looking for.
  1247. A symnode also have a pointer to the treenode which defines the symbol.
  1248. The
  1249. .B symtabs
  1250. themselves are also chained,
  1251. the chain implements a stack of declarationlevels.
  1252. The symtab which is created when the scope of a procedure is entered
  1253. is also attached to that procedure.
  1254. When a procedure is entered we create a new symtab, push it onto the stack,
  1255. parse the procedure and pop the stack.
  1256. The symbols then visible are those that still can be reached from the stack.
  1257. .LP
  1258. The parse-tree consists of
  1259. .B treenodes
  1260. representing each declaration, statement, expression etc.
  1261. Each node except the nprogram node
  1262. has a pointer to its immediate father (giving the defining point),
  1263. to its children (if it has any) and to its right brother (if it is
  1264. a member of a list).
  1265. The top of the tree is found in the global variable
  1266. .B top .
  1267. .LP
  1268. In order to find the defining point for the identifier in the assignment,
  1269. we follow pointers from the nassign-treenode
  1270. to the nid-treenode, to the lidentifier-symnode,
  1271. and then up to the nid-treenode in the declaration.
  1272. If we want to know the type of the identifier
  1273. we proceed up to the nvar-treenode
  1274. and then down to the node giving the type in the declaration
  1275. (in our example that node would also be a nid-treenode referencing a
  1276. linteger-symnode that represents the identifier "integer").
  1277. There is a function
  1278. .B typeof
  1279. that performs exactly this operation.
  1280. It will return a pointer to a npredef-, nsubrange-, nscalar-, nptr-
  1281. narray-, nrecord-, nfileof- or nsetof-treenode.
  1282. In those cases where the translator pays attention to types
  1283. it uses a pointer (obtained from typeof) as representation of a type.
  1284. .LP
  1285. Given the parse-tree and the layered symbol table
  1286. it is not hard to see how the translations described earlier are performed.
  1287. The one place where the code becomes more than usually complex is when a
  1288. .B write
  1289. statement with format specifications is to be translated into a call to
  1290. .B fprintf .
  1291. .bp
  1292. .NH 1
  1293. Tuning
  1294. .LP
  1295. The behaviour of the translator may be modified for some cases simply
  1296. by changing constants.
  1297. These constants are all located at the top of the program text.
  1298. .IP output 12
  1299. The translator will copy the source during input if the constant
  1300. .B echo
  1301. is true.
  1302. The copy is preceeded by the line
  1303. .DS
  1304. # ifdef PASCAL
  1305. .DE
  1306. and ended by the line
  1307. .DS
  1308. # else
  1309. .DE
  1310. and then follows the translated code
  1311. and finally
  1312. .DS
  1313. # endif
  1314. .DE
  1315. This may be used to hold both Pascal and C source in the same file.
  1316. If the Pascal part is changed the C part may be updated through:
  1317. .DS
  1318.     cpp -P -DPASCAL < orig > tmp
  1319.     ptc < tmp > new
  1320.     move new orig
  1321. .DE
  1322. assuming that
  1323. .B echo
  1324. is true and that 
  1325. .B cpp
  1326. is the standard C preprocessor.
  1327. .DS
  1328. Default value:
  1329.  
  1330.     echo        = false;
  1331. .DE
  1332. .IP comments
  1333. The translator recognizes both (* and { as comment delimiters.
  1334. They are treated as different,
  1335. allowing 1 level nested comments,
  1336. if the constant
  1337. .B diffcom
  1338. is true.
  1339. .DS
  1340. Default value:
  1341.  
  1342.     diffcomm    = false;
  1343. .DE
  1344. .IP symbols
  1345. The translator accepts default entries in case-statements provided
  1346. that the keyword defined through
  1347. .B othersym
  1348. is used in place of the constant list.
  1349. .DS
  1350. Default value:
  1351.  
  1352.     othersym    = 'otherwise ';
  1353. .DE
  1354. substitute for
  1355. .DS
  1356.     othersym    = 'otherwise%';
  1357. .DE
  1358. if that feature is undesired.
  1359. .IP
  1360. The translator accepts externally declared procedures and functions
  1361. provided that the directive defined through
  1362. .B externsym
  1363. is used in place of the keyword
  1364. .B forward .
  1365. .DS
  1366. Default value:
  1367.  
  1368.     externsym    = 'external  ';
  1369. .DE
  1370. .IP sets
  1371. Sets are implemented as arrays of
  1372. .B wordtype .
  1373. The type is assumed to hold
  1374. .B "setbits + 1"
  1375. bits numbered from 0.
  1376. .DS
  1377. Default value:
  1378.  
  1379.     wordtype    = 'unsigned short';
  1380.     setbits    = 15;
  1381. .DE
  1382. .ne 10
  1383. .IP files
  1384. The implementation of files uses a flag-word which has the type given as
  1385. .B filebits
  1386. which is assumed to hold
  1387. .B "filefill + 4"
  1388. bits.
  1389. .DS
  1390. Default value:
  1391.  
  1392.     filebits    = 'unsigned short';
  1393.     filefill    = 12;
  1394. .DE
  1395. .ne 20
  1396. .IP stmts
  1397. If the Pascal source is known to be "normal" in the sense that for-loops
  1398. always have an upper bound that is less than the maximum value of the
  1399. type of the loop-variable, and in the sense that the upper bound doesn't
  1400. change by computations inside the loop, then the translator may generate
  1401. a more natural code.
  1402. I.e:
  1403. .DS
  1404. for i := 1 to 10 do ;
  1405. .DE
  1406. becomes
  1407. .DS
  1408. for (i = 1; i <= 10; i++) ;
  1409. .DE
  1410. Since the requirements cannot be determined by the translator itself
  1411. this kind of code is generated when the constant
  1412. .B lazyfor
  1413. is true.
  1414. .DS
  1415. Default value:
  1416.  
  1417.     lazyfor    = false;
  1418. .DE
  1419. .ne 10
  1420. .IP new
  1421. The second and following parameters to the procedure
  1422. .B new
  1423. will be ignored if the constant
  1424. .B unionnew
  1425. is false.
  1426. .DS
  1427. Default value:
  1428.  
  1429.     unionnew    = true;
  1430. .DE
  1431. .ne 10
  1432. .IP strings
  1433. All identifiers and strings are stored in the translator with the special
  1434. character having the ordinal value
  1435. .B null
  1436. as endmarker.
  1437. Hence, that character can not occur in strings in the Pascal source.
  1438. .DS
  1439. Default value:
  1440.  
  1441.     null        = 0;
  1442. .DE
  1443. .ne 20
  1444. .IP types
  1445. The names of predefined types are given by the constants:
  1446. .B inttyp ,
  1447. .B chartyp ,
  1448. .B floattyp ,
  1449. and
  1450. .B doubletyp .
  1451. .DS
  1452. Default value:
  1453.  
  1454.     inttyp        = 'int';
  1455.     chartyp    = 'char';
  1456.     floattyp    = 'float';
  1457.     doubletyp    = 'double';
  1458. .DE
  1459. The typename for real variables and functions defined by the user
  1460. is given by the constant
  1461. .B realtyp .
  1462. .DS
  1463. Default value:
  1464.  
  1465.     realtyp    = doubletyp;
  1466. .DE
  1467. The typename for procedures is given by the constant
  1468. .B voidtyp .
  1469. .DS
  1470. Default value:
  1471.  
  1472.     voidtyp    = 'void';
  1473. .DE
  1474. .ne 10
  1475. .IP i/o
  1476. The default fieldwidths for integer and real values written on textfiles
  1477. are given by the constants
  1478. .B intlen
  1479. and
  1480. .B fixlen .
  1481. .DS
  1482. Default value:
  1483.  
  1484.     intlen    = 10;
  1485.     fixlen    = 20;
  1486. .DE
  1487. .IP types
  1488. A table in the translator gives the mapping from Pascal
  1489. integer subrange types to C arithmetic types.
  1490. The table is initialized by code located at the end of procedure
  1491. .I initialize
  1492. giving the following default configuration:
  1493. .TS
  1494. l l l
  1495. r r l .
  1496. Low bound    High bound    Selected type
  1497. .sp
  1498. 0    255    unsigned char
  1499. -128    127    char
  1500. 0    65535    unsigned short
  1501. -32768    32767    short
  1502. -2147483647    2147483647    long
  1503. .TE
  1504.